#include <arpa/inet.h>     // inet_pton
#include <netinet/in.h>    // sockaddr_in
#include <string.h>        
#include <sys/socket.h>    // socket、connect、recv、send
#include <pthread.h>       
#include <stdlib.h>        
#include <unistd.h>        // close
#include <stdio.h>       

#define BUFFER_SIZE 1024   // 定义缓冲区大小

// step 1# 接收服务器发送的消息的线程函数
void *receive_message(void *arg) {
    int sockfd = *((int *)arg);                   // 客户端套接字
    char buffer[BUFFER_SIZE];                     // 消息缓冲区
    int bytes_received;

    // step 1.1# 循环接收服务器发来的消息
    while ((bytes_received = recv(sockfd, buffer, BUFFER_SIZE - 1, 0)) > 0) {
        buffer[bytes_received] = '\0';            // 添加字符串结束符
        printf("%s\n", buffer);                   // 打印消息
    }

    // step 1.2# 服务器断开连接
    printf("与服务器断开连接。\n");
    pthread_exit(NULL);                           // 退出线程
}

// step 2# 显示菜单选项函数
void show_menu() {
    printf("\n--- 局域网聊天室客户端菜单 ---\n");
    printf("1. 发送消息\n");
    printf("2. 查看在线用户\n");
    printf("3. 退出\n");
    printf("请输入你的选择: ");
}

// step 3# 客户端主函数
int main() {
    // step 3.1# 创建客户端套接字
    int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0); // 创建 TCP 套接字

    // step 3.2# 设置服务器地址
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;                                  // 使用 IPv4
    inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr);            // 设置服务器 IP（本地）
    server_addr.sin_port = htons(8080);                                // 设置服务器端口

    // step 3.3# 连接服务器
    connect(client_socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)); // 连接服务器

    // step 3.4# 发送用户名
    printf("连接成功。\n请输入用户名：");
    char username[BUFFER_SIZE];
    fgets(username, BUFFER_SIZE, stdin);                 // 获取用户名
    username[strcspn(username, "\n")] = '\0';            // 去掉换行符
    send(client_socket_fd, username, strlen(username), 0); // 发送用户名到服务器

    // step 3.5# 创建接收消息的线程
    pthread_t tid;
    pthread_create(&tid, NULL, receive_message, &client_socket_fd); // 创建线程接收服务器消息

    // step 3.6# 主线程进入消息交互循环
    int choice;
    char buffer[BUFFER_SIZE];
    while (1) {
        show_menu();                           // 显示操作菜单
        if (scanf("%d", &choice) != 1) {       // 处理非法输入
            while (getchar() != '\n');         // 清除缓冲区
            continue;
        }
        while (getchar() != '\n');             // 吃掉输入后的换行符

        // step 3.7# 根据菜单选项执行操作
        switch (choice) {
            case 1:
                // step 3.7.1# 输入并发送普通消息
                printf("请输入消息（格式：目标用户名:消息内容）：");
                fgets(buffer, BUFFER_SIZE, stdin);                       // 输入消息
                buffer[strcspn(buffer, "\n")] = '\0';                    // 去掉换行符
                send(client_socket_fd, buffer, strlen(buffer), 0);      // 发送消息
                break;
            case 2:
                // step 3.7.2# 请求在线用户列表
                strcpy(buffer, "GET_ONLINE_USERS");                      // 特殊指令
                send(client_socket_fd, buffer, strlen(buffer), 0);      // 发送给服务器
                break;
            case 3:
                // step 3.7.3# 退出程序
                close(client_socket_fd);                                 // 关闭连接
                return 0;                                                // 退出程序
        }
    }
    return 0;
}
